#include "DIM230.h"

#include "GlobalDefinitions.h"
#include "Timer0.h"
#include <util/delay.h>

#define _triac_delay _delay_us(30);
typedef void DimTurnOnOff(void);

void turnDim0On(void);
void turnDim0Off(void);
void turnDim1On(void);
void turnDim1Off(void);
void turnDim2On(void);
void turnDim2Off(void);

typedef struct {
	DimTurnOnOff *turnOn;
	DimTurnOnOff *turnOff;
	uint8_t value;
}DIM;

DIM dim0,dim1,dim2;

typedef struct {
	uint8_t current :2;
	uint8_t firstEsecond :1;
	uint8_t secondEthird :1;
	uint8_t ch0_on :1;
	uint8_t ch1_on :1;
	uint8_t ch2_on :1;
	DIM* aDIM[3];
} COMP_ORDER;
COMP_ORDER comp_order;


void DIM230_init(void) {
	//Initializing structs
	dim0.turnOn = &turnDim0On;
	dim0.turnOff = &turnDim0Off;
	dim1.turnOn = &turnDim1On;
	dim1.turnOff = &turnDim1Off;
	dim2.turnOn = &turnDim2On;
	dim2.turnOff = &turnDim2Off;

	Timer0_init();
	//DDRD |= (0 << PD3); // PD3 as input

	SET_BIT(PORTE, PE2); //turn off dimm 0
	SET_BIT(PORTD, PD4); //turn off dimm 1
	SET_BIT(PORTD, PD5); //turn off dimm 2

	SET_BIT(DDRE, PE2); //dimm 0 as output
	SET_BIT(DDRD, PD4); //dimm 1 as output
	SET_BIT(DDRD, PD5); //dimm 2 as output


	EICRA |= (1 << ISC31) | (0 << ISC30); //falling edge of INT3
	EIMSK |= (1 << INT3);

}

void DIM230_calcValues(void) {
	//converting percentage value into timer ticks
	dim0.value = (TIMER0_RESOLUTION - ((s_data.dimm_ch0 * TIMER0_RESOLUTION)
			/ 100)) + TIMER0_OFFSET;
	dim1.value = (TIMER0_RESOLUTION - ((s_data.dimm_ch1 * TIMER0_RESOLUTION)
			/ 100)) + TIMER0_OFFSET;
	dim2.value = (TIMER0_RESOLUTION - ((s_data.dimm_ch2 * TIMER0_RESOLUTION)
			/ 100)) + TIMER0_OFFSET;

	//determining if the channels must be 100% on, if yes the triac remains on
	if (dim0.value == TIMER0_OFFSET) {
		comp_order.ch0_on = 1;
	} else {
		comp_order.ch0_on = 0;
	}

	if (dim1.value == TIMER0_OFFSET) {
		comp_order.ch1_on = 1;
	} else {
		comp_order.ch1_on = 0;
	}

	if (dim2.value == TIMER0_OFFSET) {
		comp_order.ch2_on = 1;
	} else {
		comp_order.ch2_on = 0;
	}

	//determining the order of timer compare values
	if (dim0.value < dim1.value) {
		if (dim0.value < dim2.value) {
			if (dim1.value < dim2.value) {
				comp_order.aDIM[0] = &dim0;
				comp_order.aDIM[1] = &dim1;
				comp_order.aDIM[2] = &dim2;
			} else {
				comp_order.aDIM[0] = &dim0;
				comp_order.aDIM[1] = &dim2;
				comp_order.aDIM[2] = &dim1;
			}
		} else {
			comp_order.aDIM[0] = &dim2;
			comp_order.aDIM[1] = &dim0;
			comp_order.aDIM[2] = &dim1;		}
	} else {
		if (dim0.value < dim2.value) {
			comp_order.aDIM[0] = &dim1;
			comp_order.aDIM[1] = &dim0;
			comp_order.aDIM[2] = &dim2;
		} else {
			if (dim1.value < dim2.value) {
				comp_order.aDIM[0] = &dim1;
				comp_order.aDIM[1] = &dim2;
				comp_order.aDIM[2] = &dim0;
			} else {
				comp_order.aDIM[0] = &dim2;
				comp_order.aDIM[1] = &dim1;
				comp_order.aDIM[2] = &dim0;
			}
		}
	}

	//determining if values are equal
	if (comp_order.aDIM[0]->value == comp_order.aDIM[1]->value) {
		comp_order.firstEsecond = 1;
	} else {
		comp_order.firstEsecond = 0;
	}

	if (comp_order.aDIM[1]->value == comp_order.aDIM[2]->value) {
		comp_order.secondEthird = 1;
	} else {
		comp_order.secondEthird = 0;
	}

}

ISR (INT3_vect)
{
	TCNT0 = TIMER0_OFFSET;
	comp_order.current = 0;
	OCR0 = comp_order.aDIM[0]->value;

	//if 100% turn on, else turn triac off
	if (comp_order.ch1_on) {
		CLEAR_BIT(PORTE, PE2); //turn on dimm 0
	}else{
		SET_BIT(PORTE, PE2); //turn off dimm 0
	}

	if (comp_order.ch1_on) {
		CLEAR_BIT(PORTD, PD4); //turn on dimm 0
	}else{
		SET_BIT(PORTD, PD4); //turn off dimm 0
	}

	if (comp_order.ch2_on) {
		CLEAR_BIT(PORTD, PD5); //turn on dimm 0
	}else{
		SET_BIT(PORTD, PD5); //turn off dimm 0
	}
}

ISR (TIMER0_COMP_vect)
{
	switch(comp_order.current){
	case 0:
		if(comp_order.firstEsecond){
			if(comp_order.secondEthird){
				comp_order.aDIM[0]->turnOn();
				comp_order.aDIM[1]->turnOn();
				comp_order.aDIM[2]->turnOn();
				_triac_delay
				comp_order.aDIM[0]->turnOff();
				comp_order.aDIM[1]->turnOff();
				comp_order.aDIM[2]->turnOff();
			}else{
				comp_order.aDIM[0]->turnOn();
				comp_order.aDIM[1]->turnOn();
				_triac_delay
				comp_order.aDIM[0]->turnOff();
				comp_order.aDIM[1]->turnOff();
				comp_order.current = 2;
				OCR0 = comp_order.aDIM[2]->value;
			}
		}else{
			comp_order.aDIM[0]->turnOn();
			_triac_delay
			comp_order.aDIM[0]->turnOff();
			comp_order.current = 1;
			OCR0 = comp_order.aDIM[1]->value;
		}
		break;
	case 1:
		if(comp_order.secondEthird){
			comp_order.aDIM[1]->turnOn();
			comp_order.aDIM[2]->turnOn();
			_triac_delay
			comp_order.aDIM[1]->turnOff();
			comp_order.aDIM[2]->turnOff();
		}else{
			comp_order.aDIM[1]->turnOn();
			_triac_delay;
			comp_order.aDIM[1]->turnOff();
			comp_order.current = 2;
			OCR0 = comp_order.aDIM[2]->value;
		}
		break;
	case 2:
		comp_order.aDIM[2]->turnOn();
		_triac_delay
		comp_order.aDIM[2]->turnOff();
		break;
	};
}

void turnDim0On(void){
	CLEAR_BIT(PORTE, PE2); //turn on dimm 0
}
void turnDim0Off(void){
	SET_BIT(PORTE, PE2); //turn on dimm 0
}
void turnDim1On(void){
	CLEAR_BIT(PORTD, PD4); //turn on dimm 1
}
void turnDim1Off(void){
	SET_BIT(PORTD, PD4); //turn on dimm 1
}
void turnDim2On(void){
	CLEAR_BIT(PORTD, PD5); //turn on dimm 1
}
void turnDim2Off(void){
	SET_BIT(PORTD, PD5); //turn on dimm 1
}


